
inline quat::quat( float x0/* = 0.0f*/, float y0/* = 0.0f*/, float z0/* = 0.0f*/, float w0/* = 1.0f*/) : 
	x(x0), y(y0), z(z0), w(w0) 
{
	assert( (*this).check() );
}

inline quat::quat(const quat& q) : x(q.x), y(q.y), z(q.z), w(q.w)
{
	assert(check());
}

inline quat& quat::operator+=( const quat& o )
{
	assert( o.check() );
	assert( (*this).check() );
	x += o.x;
	y += o.y;
	z += o.z;
	w += o.w;
	return *this;
}

inline quat& quat::operator-=( const quat& o )
{
	assert( o.check() );
	assert( (*this).check() );
	x -= o.x;
	y -= o.y;
	z -= o.z;
	w -= o.w;
	return *this;
}

inline quat& quat::operator*=( float s )
{
	assert( slm::check(s) );
	assert( (*this).check() );
	x *= s;
	y *= s;
	z *= s;
	w *= s;
	return *this;
}

inline quat& quat::operator*=( const quat& o )
{
	*this = *this * o;
	return *this;
}

inline float& quat::operator[]( size_t i )
{
	assert( i < SIZE );
	return _v[i];
}

inline quat quat::operator+( const quat& o ) const
{
	assert( o.check() );
	assert( (*this).check() );
	return quat(x+o.x,y+o.y,z+o.z,w+o.w);
}

inline quat quat::operator-( const quat& o ) const
{
	assert( o.check() );
	assert( (*this).check() );
	return quat(x-o.x,y-o.y,z-o.z,w-o.w);
}

inline quat quat::operator-() const
{
	assert( (*this).check() );
	return quat(-x,-y,-z,-w);
}

inline quat quat::operator*( float s ) const
{
	return mul(s);
}

inline const float& quat::operator[]( size_t i ) const
{
	assert( i < SIZE );
	assert( (*this).check() );
	return _v[i];
}

inline const vec4& quat::xyzw() const
{
	return *(const vec4*)&x;
}

inline quat quat::conjugate()const
{
	return quat( -x, -y, -z, w );
}

inline float quat::dot(const quat& b )const
{
	assert( this->check() );
	assert( b.check() );

	const float res = x*b.x + y*b.y + z*b.z + w*b.w;

	assert( res >= -FLT_MAX && res <= FLT_MAX );
	return res;
}

inline bool quat::operator==( const quat& o ) const
{
	return x == o.x && y == o.y && z == o.z && z == o.z && w == o.w;
}

inline bool quat::operator!=( const quat& o ) const
{
	return x != o.x || y != o.y || z != o.z || z != o.z || w != o.w;
}

inline vec3 quat::operator*(const vec3& v3)const
{
	return mul(v3);
}

inline vec3 quat::mul(const vec3& v3)const
{
	vec3 uv, uuv;
	vec3 qvec(x, y, z);
	uv = qvec.cross(v3);
	uuv = qvec.cross(uv);
	uv *= (2.0f * w);
	uuv *= 2.0f;

	return v3 + uv + uuv;
}

inline quat quat::mul(float fv)const
{
	SLMATH_VEC_ASSERT( slm::check(fv) );
	SLMATH_VEC_ASSERT( (*this).check() );
	return quat(x * fv,y * fv,z * fv,w * fv);
}

inline quat quat::neg()const
{
	return quat(-x, -y, -z, -w);
}

#ifdef SLMATH_AUTO_DX_CONVERSION
inline quat& quat::operator = (const D3DXQUATERNION& dxquat)
{
	this->x = dxquat.x;
	this->y = dxquat.y;
	this->z = dxquat.z;
	this->w = dxquat.w;
	return *this;
}

inline quat::operator D3DXQUATERNION()const
{
	return D3DXQUATERNION(x, y, z, w);
}
#endif // SLMATH_AUTO_DX_CONVERSION

inline std::ostream& operator << (std::ostream& stream, const quat& q)
{
	stream << "quat(" << q.x << "," << q.y << "," << q.z << "," << q.w << ")";
	return stream;
}

inline std::wostream& operator << (std::wostream& stream, const quat& q)
{
	stream << L"quat(" << q.x << L"," << q.y << L"," << q.z << L"," << q.w << L")";
	return stream;
}

inline quat operator * (float fv, const quat& q)
{
	return q.mul(fv);
}

inline bool equal(const quat& left, const quat& right, float tolerance)
{
	float fcos = left.dot(right);
	return slm::equal(fcos, 1.0f, tolerance);
}
// This file is part of 'slm' C++ library. Copyright (C) 2009 Jani Kajala (kajala@gmail.com). See http://sourceforge.net/projects/slm/
